package com.m4399.ea.sdk;



import com.m4399.ea.sdk.ssl.HttpsHostnameVerifier;
import com.m4399.ea.sdk.ssl.HttpsSSLSocketFactory;

import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.concurrent.TimeoutException;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;

/**
 * 网络请求工具类
 *
 * @author 陈宝阳
 * @create 2019/5/15
 */
public class HttpUtils {

  private static final String REQ_PROPERTY_CONNECTION = "Connection";
  private static final String REQ_VALUE_CONNECTION = "Keep-Alive";

  /**
   * http请求方法 - GET
   */
  private static final String HTTP_METHOD_GET = "GET";
  /**
   * http请求方法 - POST
   */
  private static final String HTTP_METHOD_POST = "POST";
  /**
   * utf-8字符集
   */
  private static final String CHARSET_UTF8 = "UTF-8";

  /**
   * 连接超时时间，7秒
   */
  private static final int CONNECT_TIMEOUT = 7 * 1000;

  /**
   * 读取超时时间
   */
  private static final int READ_TIMEOUT = 7 * 1000;

  /**
   * get网络请求
   * @param baseUrl
   */
  public static void requestGet(String baseUrl, Map<String, Object> params,
      OnHttpRequestListener listener){
    HttpURLConnection urlConnection = null;
    try {

      String paramStr = buildParams(params);
      if (paramStr != "") {
        baseUrl = baseUrl + "?" + paramStr;
      }

      urlConnection = openURLConnection(baseUrl);
      urlConnection.setRequestMethod(HTTP_METHOD_GET);
      urlConnection.connect();


      parseResponse(urlConnection, listener);

    } catch (Exception e) {
      if (listener != null) {
        listener.onResponseError(-4000, e.getMessage());
      }
    }finally {
      closeConnection(urlConnection);
    }
  }

  public static void requestPost(String url,  Map<String, Object> params,
      OnHttpRequestListener listener) {
    requestPost(url, params, null, listener);
  }

  /**
       * POST参数
       * @param baseUrl
       * @param params
       * @param headers 用户信息串，
       * @param listener
       */
  public static void requestPost(String baseUrl,
       Map<String,Object> params, Map<String, String> headers,
      OnHttpRequestListener listener) {

    HttpURLConnection urlConnection = null;
    try {
      urlConnection = openURLConnection(baseUrl);
      if(headers != null && !headers.isEmpty()) {

        for (String key : headers.keySet()) {
           urlConnection.setRequestProperty(key, headers.get(key));
        }
      }

      urlConnection.setRequestMethod(HTTP_METHOD_POST);

      /**
       * 设置输入
       */
      urlConnection.setDoInput(true);
      /**
       * 设置输出
       */
      urlConnection.setDoOutput(true);

      String newParams = buildParams(params);

      //参数写入
      DataOutputStream outputStream = new DataOutputStream(
          urlConnection.getOutputStream()
      );
      outputStream.write(newParams.getBytes());
      outputStream.flush();
      outputStream.close();

      //返回值解析
      parseResponse(urlConnection, listener);


    } catch (Exception e) {
      if(listener != null) {
        if (e instanceof UnknownHostException ||
            e instanceof ConnectException ||
            e instanceof TimeoutException ||
            e instanceof ProtocolException ||
            e instanceof IOException ||
            e instanceof EOFException ||
            e instanceof SSLException ||
            e instanceof SSLHandshakeException) {
          listener.onResponseError(-4001, "网络连接异常");
        }else  {
          listener.onResponseError(-4000, e.getMessage());
        }
      }

    }finally {
      closeConnection(urlConnection);
    }

  }

  /**
   * POST参数
   * @param baseUrl
   * @param jsonParam
   * @param listener
   */
  public static void requestPost(String baseUrl,
                                 JSONObject jsonParam,
                                 OnHttpRequestListener listener) {

    HttpURLConnection urlConnection = null;
    try {
      urlConnection = openURLConnection(baseUrl);
      urlConnection.setRequestMethod(HTTP_METHOD_POST);

      /**
       * 设置输入
       */
      urlConnection.setDoInput(true);
      /**
       * 设置输出
       */
      urlConnection.setDoOutput(true);

      /**
       * 参数写入
       */
      PrintWriter printWriter = new PrintWriter(urlConnection.getOutputStream());
      printWriter.write(jsonParam.toString());
      printWriter.flush();

      //返回值解析
      parseResponse(urlConnection, listener);

      printWriter.close();

    } catch (Exception e) {
      if (listener != null) {
        if(e instanceof UnknownHostException ||
                e instanceof ConnectException ||
                e instanceof TimeoutException ||
                e instanceof ProtocolException ||
                e instanceof IOException ||
                e instanceof EOFException ||
                e instanceof SSLException ||
                e instanceof SSLHandshakeException){
          listener.onResponseError(-4001, "请检测网络");
        }else{
          listener.onResponseError(-4000, e.getMessage());
        }

      }

    }finally {
      closeConnection(urlConnection);
    }



  }

  /**
   * 解析response信息
   * @param urlConnection
   * @param listener
   */
  private static void parseResponse(HttpURLConnection urlConnection,
      OnHttpRequestListener listener) throws Exception {
    int httpStatus = urlConnection.getResponseCode();
    if (isOK(httpStatus)) {
      String result = streamToString(urlConnection.getInputStream());
      if (listener != null) {
        listener.onResponseSuccess(result);
      }

    } else {
      if (listener != null) {
        listener.onResponseError(httpStatus, urlConnection.getResponseMessage());
      }

    }
  }

  /**
   * 网络请求是否成功
   */
  private static boolean isOK(int responseCode) {
    return responseCode == HttpURLConnection.HTTP_OK;
  }


  /**
   * 参数构建
   * @param params
   * @return
   */
  private static String buildParams(Map<String, Object> params){
    if (null == params || params.isEmpty()) {
      return "";
    }

    StringBuilder paramSB = new StringBuilder();

    boolean isFirst = true;

    for (String key : params.keySet()) {
      if(isFirst) {
        isFirst = false;
      } else {
        paramSB.append("&");
      }

      paramSB.append(key).append("=").append(URLEncoder.encode(String.valueOf(params.get(key))));
    }
    String result = paramSB.toString();
    return result;
  }

  /**
   * 关闭连接
   * @param connection
   */
  private static void closeConnection(HttpURLConnection connection) {
    if (null != connection) {
      connection.disconnect();
    }
  }

  /**
   * 打开一个连接
   * @param baseUrl
   * @return
   * @throws IOException
   */
  private static HttpURLConnection openURLConnection(String baseUrl)
      throws IOException {
    URL url = new URL(baseUrl);
    HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
    //添加https的认证
    if (baseUrl.toUpperCase().startsWith("HTTPS")) {
      HttpsURLConnection httpsURLConnection = (HttpsURLConnection) urlConnection;
      httpsURLConnection.setHostnameVerifier(new HttpsHostnameVerifier());
      httpsURLConnection.setSSLSocketFactory(HttpsSSLSocketFactory.factory());
      urlConnection = httpsURLConnection;
    }
    // Workaround for the M release HttpURLConnection not observing the
    // HttpURLConnection.setFollowRedirects() property.
    // https://code.google.com/p/android/issues/detail?id=194495
    urlConnection.setInstanceFollowRedirects(HttpURLConnection.getFollowRedirects());
    //urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");

    //设置超时时间
    urlConnection.setConnectTimeout(CONNECT_TIMEOUT);
    urlConnection.setReadTimeout(READ_TIMEOUT);

    //设置连接类型
    urlConnection.setRequestProperty(REQ_PROPERTY_CONNECTION,
        REQ_VALUE_CONNECTION);

    //不使用缓存
    urlConnection.setUseCaches(false);

    return urlConnection;
  }

  /**
   * 流转换为string字符串
   * @param inputStream
   * @return
   * @throws IOException
   */
  private static String streamToString(InputStream inputStream)
      throws IOException {

    BufferedReader br = new BufferedReader(new InputStreamReader(inputStream,
        CHARSET_UTF8));

    StringBuffer sb = new StringBuffer();

    String line = null;

    while ((line = br.readLine()) != null) {
      sb.append(line);
    }

    br.close();

    return sb.toString();

  }

  /**
   * Http网络请求监听
   */
  public interface OnHttpRequestListener {

    /**
     * 网络请求成功
     * @param response
     */
    void onResponseSuccess(String response) throws Exception;

    /**
     * 网络请求失败
     * @param code
     * @param errorMessage
     */
    void onResponseError(int code, String errorMessage);
  }

}
